﻿using System.Collections.Concurrent;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Windows;
using System.Windows.Controls;
using AutoClick.capture;
using AutoClick.native;
using AutoClick.ui;
using AutoClick.utils;
using Emgu.CV;
using H.Hooks;
using Microsoft.Win32;
using Newtonsoft.Json.Linq;
using Notifications.Wpf;
using static AutoClick.utils.SafeConvertUtil;
using Exception = System.Exception;

namespace AutoClick;

/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow
{
    private ProcessInfo? _processInfo;

    private bool _isRunning;

    private double _matchValue;

    private readonly LowLevelKeyboardHook _keyboardHook;

    public MainWindow()
    {
        InitializeComponent();

        Closed += StatusWindow_Closed;

        // 初始化全局键盘钩子
        _keyboardHook = new LowLevelKeyboardHook();
        _keyboardHook.Down += KeyboardHook_Down;
        _keyboardHook.Start();

        // 初始化配置路径
        ConfigTextBox.Text = Path.GetFullPath(AppDomain.CurrentDomain.BaseDirectory + "./resource/config.json");

        // 初始化进程
        FindProcess();
    }

    private void FindProcess()
    {
        var filepath = ConfigTextBox.Text;
        if (string.IsNullOrWhiteSpace(filepath) || !File.Exists(filepath)) return;
        var fileContent = File.ReadAllText(filepath);
        var jsonObj = JObject.Parse(fileContent);
        var processName = ObjToString(jsonObj["ProcessName"]);

        var processes = Process.GetProcessesByName(processName);

        if (processes.Length > 0)
        {
            _processInfo = new ProcessInfo
            {
                ProcessName = processes[0].ProcessName,
                Pid = processes[0].Id
            };
            PidTextBox.Text = $"{_processInfo.ProcessName}({_processInfo.Pid})";
        }
    }

    private void KeyboardHook_Down(object? sender, KeyboardEventArgs e)
    {
        // 检查是否按下 F12 键
        if (!e.Keys.Are(Key.F12)) return;
        // 切换运行
        if (IsRunning)
        {
            IsRunning = false;
        }
        else
        {
            Dispatcher.InvokeAsync(StartTask);
        }
    }

    private void StatusWindow_Closed(object? sender, EventArgs e)
    {
        IsRunning = false;
        _keyboardHook.Stop();
        Environment.Exit(0);
    }


    private bool IsRunning
    {
        get => _isRunning;
        set
        {
            if (_isRunning == value) return;

            _isRunning = value;
            // 其他线程更新此控件
            Dispatcher.Invoke(() => { IsRunningCheckBox.IsChecked = _isRunning; });

            ShowNotification();
        }
    }

    private void ShowNotification()
    {
        new NotificationManager().Show(new NotificationContent
        {
            Title = "AutoClick",
            Message = IsRunning ? "Running" : "Stopped",
            Type = IsRunning ? NotificationType.Success : NotificationType.Error,
        });
    }


    private void PidBtn_OnClick(object sender, RoutedEventArgs e)
    {
        var processList = new ProcessList();
        processList.ShowDialog();

        if (processList.SelectedProcess == null) return;
        _processInfo = processList.SelectedProcess;
        var pid = processList.SelectedProcess.Pid;
        var pName = processList.SelectedProcess.ProcessName;
        PidTextBox.Text = $"{pName}({pid})";
    }

    private void ConfigBtn_OnClick(object sender, RoutedEventArgs e)
    {
        var openFileDialog = new OpenFileDialog
        {
            Title = "Select a JSON file",
            InitialDirectory = AppDomain.CurrentDomain.BaseDirectory,
            Filter = "JSON File (*.json)|*.json|All Files (*.*)|*.*",
            FilterIndex = 1,
            Multiselect = false
        };

        var result = openFileDialog.ShowDialog();

        if (result != true) return;
        var fileName = openFileDialog.FileName;
        CheckConfig(fileName);
        ConfigTextBox.Text = fileName;
    }

    private void StartBtn_OnClick(object sender, RoutedEventArgs e)
    {
        StartTask();
        // test code
        // var gameCapture = GameCaptureFactory.CreateGameCapture(((ComboBoxItem)CaptureMethodComboBox.SelectedValue).Content.ToString());
        // var bitmap = gameCapture.Capture(CaptureUtil.GetWindowHandle("rider64"));
        // bitmap?.Save("aaaaaa.png");
    }

    private void StopBtn_OnClick(object sender, RoutedEventArgs e)
    {
        IsRunning = false;
    }

    private JObject? CheckConfig(string filepath)
    {
        if (IsRunning)
        {
            MessageBox.Show("Config is already running");
            return null;
        }

        if (string.IsNullOrWhiteSpace(filepath))
        {
            MessageBox.Show("Please select a valid JSON file");
            return null;
        }

        if (!File.Exists(filepath))
        {
            MessageBox.Show("File does not exist");
            return null;
        }

        if (_processInfo == null)
        {
            MessageBox.Show("Please select a process first");
            return null;
        }

        try
        {
            var fileContent = File.ReadAllText(filepath);
            var jsonObj = JObject.Parse(fileContent);
            var processName = ObjToString(jsonObj["ProcessName"]);


            if (processName == _processInfo.ProcessName)
            {
                return jsonObj;
            }

            MessageBox.Show($"Config[{_processInfo.ProcessName}] Not Found", "Info");
            return null;
        }
        catch (Exception ex)
        {
            MessageBox.Show($"Error reading the file: {ex.Message}", "Error", MessageBoxButton.OK,
                MessageBoxImage.Error);
        }

        return null;
    }

    private void StartTask()
    {
        var filepath = ConfigTextBox.Text;
        var captureMethod = ((ComboBoxItem)CaptureMethodComboBox.SelectedValue).Content.ToString();
        var config = CheckConfig(filepath);
        if (config == null) return;
        config["curDir"] = Path.GetDirectoryName(filepath);
        _matchValue = ToDouble(config["MatchValue"]);

        if (config == null)
        {
            throw new Exception("Config is null");
        }

        if (_processInfo == null)
        {
            throw new Exception("目标程序无效");
        }

        WindowState = WindowState.Minimized;

        var t = new Thread(_ =>
        {
            try
            {
                IsRunning = true;

                // Console.WriteLine($"Starting task:{_processInfo.ProcessName}");

                var curDir = ObjToString(config["curDir"]);
                var resDir = ObjToString(config["ResourcePath"]);

                var iconsMatMap = new Dictionary<string, Mat>();

                var handle = CaptureUtil.GetWindowHandle(_processInfo.ProcessName);
                User32.ShowWindow(handle, CaptureUtil.SW_RESTORE);
                User32.SetForegroundWindow(handle);

                var icons = ToJArray(config["Icons"]);

                var indexMap = new Dictionary<string, int>();
                for (var i = 0; i < icons.Count; i++)
                {
                    indexMap[ObjToString(icons[i])] = i;
                }

                var actions = ToJArray(config["Actions"]);

                var gameCapture =
                    GameCaptureFactory.CreateGameCapture(captureMethod ??
                                                         throw new InvalidEnumArgumentException("截图类型不能为空"));

                while (IsRunning)
                {
                    // 截图
                    var bitmap = gameCapture.Capture(handle);
                    if (bitmap == null)
                    {
                        throw new Exception("Capture failed! method: Dxgi");
                    }

                    User32.GetWindowRect(handle, out var rect);
                    var src = CaptureUtil.BitmapToEmguMat(bitmap);

                    var results = new ConcurrentDictionary<string, MatchResult>();

                    // 并行判断是否匹配
                    Parallel.ForEach(icons, icon =>
                    {
                        var iconStr = ObjToString(icon);
                        var iconPath = $"{curDir}/{resDir}/{iconStr}";

                        var iconMat = iconsMatMap.GetValueOrDefault(iconPath);
                        var matchResult = iconMat != null
                            ? CaptureUtil.Match(src, iconPath, iconMat, true)
                            : CaptureUtil.Match(src, iconPath);

                        iconsMatMap[iconPath] = matchResult.Dst;

                        if (IsMatched(matchResult))
                        {
                            results[iconStr] = matchResult;
                        }
                    });

                    if (!results.IsEmpty)
                    {
                        // 排序
                        var keys = results.Keys;

                        // 对键进行排序，按照原始列表中的索引顺序
                        var sortedKeys = keys.OrderBy(key => indexMap.GetValueOrDefault(key, int.MaxValue)).ToList();

                        // 取第一个匹配的结果
                        var targetResult = results[sortedKeys[0]];

                        // Console.WriteLine($"matched: {sortedKeys[0]}, val:{targetResult.ResultValue}");

                        // Thread.Sleep(5000);
                        // 执行任务
                        ActionUtil.DoActions(rect, actions, targetResult);
                    }
                    else
                    {
                        // Console.WriteLine($"icons not match at: {DateTime.Now:yyyy-MM-dd HH:mm:ss.fff}");
                    }
                }
            }
            catch (Exception e)
            {
                IsRunning = false;
                Console.Error.WriteLine(e);
            }
        })
        {
            IsBackground = true
        };

        t.Start();
    }


    private bool IsMatched(MatchResult matchResult)
    {
        if (_matchValue > 0)
        {
            return matchResult.ResultValue >= _matchValue;
        }

        return false;
    }
}